package com.javasee.data;

import com.javasee.common.dbsharding.DbShardingMyBatisInterceptor;
import com.javasee.common.dbsharding.DbShardingProperties;
import com.javasee.common.dbsharding.DbShardingRouterFactory;
import com.javasee.common.dbsharding.DbShardingRoutingDataSource;
import com.javasee.common.module.ModuleEnable;
import com.javasee.common.module.ModuleEnableConst;
import com.zaxxer.hikari.HikariDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

@ModuleEnable(ModuleEnableConst.DBSHARDING)
@Slf4j
@Configuration
@EnableConfigurationProperties({DbShardingProperties.class})
@MapperScan(basePackages = {"com.**.mapper","org.**.mapper","net.**.mapper"},sqlSessionFactoryRef = "dbSqlSessionFactory")
public class DbShardingConfig {

    @Bean(name = "dbShardingRouterFactory")
    public DbShardingRouterFactory dbShardingRouterFactory(DbShardingProperties dbShardingProperties) {
        log.info("init DbShardingRouterFactory");
        return new DbShardingRouterFactory(dbShardingProperties);
    }

    @Bean(name = "dbDataSource")
    @Primary
    public DataSource dataSource(DbShardingProperties dbShardingProperties) {
        DbShardingRoutingDataSource dbShardingRoutingDataSource = new DbShardingRoutingDataSource();
        Map<Object, Object> targetDataSources = new HashMap();
        Map<String, DataSourceProperties> dataSources = dbShardingProperties.getDatasources();
        Iterator<Map.Entry<String, DataSourceProperties>> dbsItr = dataSources.entrySet().iterator();
        while (dbsItr.hasNext()) {
            Map.Entry<String, DataSourceProperties> entry = dbsItr.next();
            DataSourceProperties dsp = entry.getValue();
            HikariDataSource ds = dsp.initializeDataSourceBuilder().type(HikariDataSource.class).build();
            ds.setMinimumIdle(dbShardingProperties.getMinIdle());
            ds.setMaximumPoolSize(dbShardingProperties.getMaxIdle());
            ds.setIdleTimeout(dbShardingProperties.getIdleTimeout());
            ds.setMaxLifetime(dbShardingProperties.getMaxLifetime());
            targetDataSources.put(entry.getKey(), ds);
        }
        dbShardingRoutingDataSource.setTargetDataSources(targetDataSources);
        dbShardingRoutingDataSource.setDefaultTargetDataSource(targetDataSources.get("db1"));
        return dbShardingRoutingDataSource;
    }

    @Bean(name = "dbSqlSessionFactory")
    public SqlSessionFactory dbSqlSessionFactory(@Qualifier("dbDataSource") DataSource datasource,DbShardingProperties dbShardingProperties)
            throws Exception {
        SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
        bean.setDataSource(datasource);
        //bean.setTypeHandlersPackage("com.javasee.common.dbsharding.mybatis.typeHandler");
        bean.setTypeHandlersPackage(dbShardingProperties.getTypeHandlersPackage());
        bean.setMapperLocations(
                new PathMatchingResourcePatternResolver().getResources(dbShardingProperties.getMapperXmlClassPath()));
        System.out.println("dbSqlSessionFactory#dbShardingProperties.getMapperScanBasePackages() = " + DbShardingProperties.mapperScanBasePackages);
        System.out.println("dbShardingProperties.getMapperXmlClassPath() = " + dbShardingProperties.getMapperXmlClassPath());
        bean.setPlugins(new Interceptor[]{new DbShardingMyBatisInterceptor()});

        return bean.getObject();
    }

    @Bean("dbSqlSessionTemplate")
    public SqlSessionTemplate dbSqlSessionTemplate(
            @Qualifier("dbSqlSessionFactory") SqlSessionFactory sessionFactory) {
        return new SqlSessionTemplate(sessionFactory);
    }

//    @Bean
//    public MapperScannerConfigurer mapperScannerConfigurer(DbShardingProperties dbShardingProperties) {
//        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
//        System.out.println("mapperScannerConfigurer#dbShardingProperties.getMapperScanBasePackages() = " + DbShardingProperties.mapperScanBasePackages);
//        configurer.setBasePackage(DbShardingProperties.mapperScanBasePackages);
//        configurer.setSqlSessionFactoryBeanName("dbSqlSessionFactory");
//        configurer.setSqlSessionTemplateBeanName("dbSqlSessionTemplate");
//        return configurer;
//    }

//    @Bean
//    public DbShardingMyBatisInterceptor dbShardingMyBatisInterceptor() {
//        return new DbShardingMyBatisInterceptor();
//    }
}
